#include "VideoRead.h"

bool LcVideoReadExt::IF_GRAY = true;

LcVideoRead::LcVideoRead()
{
	root = "C:/Users/LC1332/Desktop/CMUWinter/VideoRead/_FGS/";
	video_name = "GOPR2382_cab";
	ext = ".avi";
	f_start = 150;
	f_end = 350;
	f_rate = 50;
	t_win = 2;
	f = 0;
	scale = 0.5;
	veb = 1;
}


void testLcVideoRead()
{
	LcVideoReadExt test;

	test.t_win = 1;
	//test.open();

	for(int k = 0;k<2;k++)
	{
		for(int i = 0;i<120;i++)
		{
			Mat frm;
			int j = test.read(frm);
			cout << i << " " << j << " ";
			cout << test.f - test.t_win<< endl;
			if(j>=0)
			{
				imshow("show",frm);
				cv::waitKey(2);
			}
		}
		test.reset();
	}

	for(int k = 0;k<2;k++)
	{
		for(int i = 0;i<5;i++)
		{
			Mat frm;
			int j = test.readNext(frm);
			if(j>=0)
			{
				imshow("show",frm);
				cv::waitKey(200);
			}
		}
		test.reset();
	}

	system("pause");
}


void testLabelRead()
{
	LcVideoReadExt test;

	test.t_win = 2;

	for(int k = 0;k<2;k++)
	{
		for(int i = 0;i<5;i++)
		{
			Mat frm;

			vector<Mat> frms;
			int j = test.readNext(frm,&frms);

			cout << "f= " << test.getf() << endl;			

			frms[2].copyTo(frm);

			//int f = test.getf();

			//test.readAtF( frm, NULL, f);

			Mat lab;
			test.getLabel(lab);
			

			if(j>=0)
			{				

				if(lab.data)
				{
					if(lab.type()==CV_8U)
						cv::cvtColor( lab, lab , CV_GRAY2RGB);

					Mat dsp;
					cv::addWeighted( lab, 0.5, frm, 0.5, 0, dsp);

					imshow("debug", dsp);

					cv::waitKey(200);
				}
			}
		}
		test.reset();
	}
	cv::waitKey(0);
}

void LcVideoRead::getLabel(Mat & lab)
{
	int id = getf();

	string msktyp = "msk_fg/";

	stringstream ss;
	ss << root + msktyp + video_name + "/" + video_name + "_maskgt_" << id <<".jpg";

	if(veb) cout << "load " << ss.str() << endl;

	lab = imread(ss.str(),0);
}


int LcVideoRead::getf()
{
	return f;
}

void LcVideoRead::reset()
{
	if(cap.isOpened())
		cap.release();
	f = 0;
}



void LcVideoRead::open()
{
	string vidfile = root + "vid/" + video_name + ext;

	cout << "Opening video: " << vidfile << endl;

	cap = VideoCapture(vidfile);

	if(!cap.isOpened())
	{
		cout << "failed to open" << endl;
		system("pause");
		exit(1);
	}

	cout << "opened" << endl;

	Mat temp;

	f = f_start-1;	

	cap.set( CV_CAP_PROP_POS_FRAMES, double(getf()+1));	

	temp.release();
}


int LcVideoRead::getN()
{
	if((f_end-f_start)%f_rate!=0)
		return (f_end-f_start)/f_rate;
	else
		return (f_end-f_start)/f_rate+1;
}




int LcVideoRead::read_one_frame(Mat & frm)
{
	Mat temp;
	f++;	

	cap >> temp;

	if(!temp.data) return 0;
	Mat temp2;
	resize(temp,temp2,Size(),scale,scale);
	temp2.copyTo(frm);	
	return 1;
}

int LcVideoRead::read(Mat & frm)
{
	if(f == 0) open();

	if(f>f_end+t_win+1) return -1;

	if(!read_one_frame(frm)) return -1;

	if(f>f_end) return -1;

	if(((f-f_start)%f_rate)!=0) return 1;
	if(f<f_start) return 1;	
	
	return 0;
}

int LcVideoRead::readNext(Mat & frm)
{
	if(f == 0) open();

	do{
		f++;
	}while((((f-f_start)%f_rate)!=0));

	cap.set( CV_CAP_PROP_POS_FRAMES, double(getf()));	

	Mat temp;

	cap >> temp;

	if(!temp.data) return 1;
	Mat temp2;
	resize(temp,temp2,Size(),scale,scale);
	temp2.copyTo(frm);

	if(f>f_end) return -1;

	return 0;
}

//=============================


void LcVideoReadExt::reset()
{
	if(cap.isOpened())
		cap.release();
	f = 0;
}


int LcImgRead::read(Mat & frm)
{
	return read(frm, NULL);
}

int LcImgRead::readNext(Mat & frm)
{
	return readNext(frm, NULL);
}


int LcImgRead::read(Mat & frm, vector<Mat> * frm_array)
{
	if(f==0)
		f = f_start-1;	

	string vidfile = root + "vid/" + video_name + "/";

	char fname[600];

	f++;

	if(f>f_end) return -1;

	sprintf(fname,"%s%d%s", vidfile.c_str(), f, ext.c_str() );

	frm = imread( fname  );	

	if(!frm.data) return -1;

	return 0;
}

int LcImgRead::readNext(Mat & frm, vector<Mat> * frm_array)
{
	if(f==0)
		f = f_start-1;	

	do{
		f++;
	}while((((f-f_start)%f_rate)!=0));

	if(f>f_end) return -1;

	string vidfile = root + "vid/" + video_name + "/";

	char fname[600];

	sprintf(fname,"%s%d%s", vidfile.c_str(), f, ext.c_str() );

	frm = imread( fname );	

	if(!frm.data) return -1;

	return 0;
}


int LcVideoReadExt::read(Mat & frm)
{
	return read(frm,NULL);
}

int LcVideoReadExt::readAtF(Mat & frm, vector<Mat> * frm_array, int f)
{
	if(f == 0) open();

	cap.set( CV_CAP_PROP_POS_FRAMES, double( f ));	

	read_one_frame(frm);

	f--;

	return 0;
}

int LcVideoReadExt::read(Mat & frm, vector<Mat> * frm_array)
{
	
	if(f == 0)
	{
		open();
		array_init();
	}

	if(f>f_end+t_win+1) return -1;

	Mat temp;

	if(!read_one_frame( temp) ) return -1;
	loop_id = loop_add( loop_id );

	int f_now = f - t_win;

	img_array[loop_id] = temp;

	img_array[ loop_minus(loop_id, t_win) ].copyTo(frm);

	if(frm_array!=NULL)
	{
		getfrms(frm_array);
	}
	
	if(f_now>f_end) return -1;

	if(f_now<t_win) return 1;
	if(((f_now-f_start)%f_rate)!=0) return 1;
	if(f_now<f_start) return 1;
	
	return 0;
}

void LcVideoReadExt::getfrms( vector<Mat> * frm_array)
{
	int id = loop_minus(loop_id, 2*t_win);

	vector< Mat > & imgs = *frm_array;

	imgs.resize( 2* t_win + 1);

	for(int i = 0;i< 1+ 2* t_win;i++)
	{
		//imgs[i] = img_array[ id ];
		img_array[ id ].copyTo(imgs[i]);
		id = loop_add( id, 1);
	}

}


int LcVideoReadExt::readNext(Mat & frm)
{
	return readNext(frm, NULL);
}

int LcVideoReadExt::readNext(Mat & frm, vector<Mat>  * frm_array)
{
	
	if(f == 0) open();

	do{
		f++;
	}while((((f-f_start)%f_rate)!=0));

	if(f>f_end) return -1;

	cap.set( CV_CAP_PROP_POS_FRAMES, double(getf()));	

	Mat temp;

	cap >> temp;

	if(!temp.data) return 1;
	Mat temp2;
	resize(temp,temp2,Size(),scale,scale);
	temp2.copyTo(frm);	


	if(frm_array != NULL )
	{
		frm_array->clear();
		frm_array->resize( 2 * t_win + 1 );

		vector< int > id;
		id.resize( 2 * t_win + 1 );
		for(int i = 0; i < 2 * t_win + 1; i++)
			id[i] = max(1,f - t_win + i);

		int last = id[0]-1;

		cap.set( CV_CAP_PROP_POS_FRAMES, double(id[0]));

		vector<Mat> & frms = *frm_array;

		for(int i = 0; i < 2 * t_win + 1; i++)
		{
			if(last != id[i])				
			{
				cap >> temp;
				resize(temp,temp2,Size(),scale,scale);
			}
			temp2.copyTo( frms[i]);
		}	
	}

	return 0;

}



int LcVideoReadExt::loop_add(int loop_id,int i)
{
	loop_id+=i;
	while(loop_id>=t_win*2+1) loop_id-=(t_win*2+1);
	return loop_id;
}

int LcVideoReadExt::loop_minus(int loop_id, int i)
{
	loop_id-=i;
	while(loop_id<0) loop_id+=(t_win*2+1);
	return loop_id;
}

void LcVideoReadExt::array_init()
{
	img_array.resize(t_win*2+1);

	loop_id = 0;//id of mid frame

	Mat first_image;

	read_one_frame( first_image );

	for(int i = 0;i<t_win*2+1;i++) img_array[i] = first_image;
	//to avoid broken build it at first

	while(f < f_start+t_win-1)
	{
		Mat temp;

		if(!read_one_frame( temp) ){
			cout << " The video is not enough long " << endl;
			exit(1);
		}

		loop_id = loop_add( loop_id );

		img_array[loop_id] = temp;
	}
}
//===================================

int LcVideoReadVec::getN()
{
	return (int) frm_id.size();
}

LcVideoReadVec::LcVideoReadVec()
{
	p = -1;
	IF_IMG = false;
}

LcVideoReadVec::LcVideoReadVec( LcVideoRead & reader )
{
	root = reader.root;
	video_name = reader.video_name;
	ext = reader.ext;

	p = -1;

	open();
}

int LcVideoReadVec::getf()
{
	return f;
}

void LcVideoReadVec::open()
{
	bool bo = false;
	bo = bo ||  ( ext == ".jpg" );
	bo = bo ||  ( ext == ".JPG" );
	bo = bo ||  ( ext == ".PNG" );
	bo = bo ||  ( ext == ".png" );

	if(bo)
	{
		IF_IMG = true;
	}
	else
	{
		string vidfile = root + "vid/" + video_name + ext;

		cout << "Opening video: " << vidfile << endl;

		cap = VideoCapture(vidfile);

		if(!cap.isOpened())
		{
			cout << "failed to open" << endl;
			system("pause");
			exit(1);
		}

		cout << "opened" << endl;		
	}

	p = -1;
}


void LcVideoReadVec::reset()
{
	if(frm_id.size()>0) f = frm_id[0]-1;
	p = -1;
}

void LcVideoReadVec::set(vector<int> & n_frm_id)
{
	frm_id = n_frm_id;
	p = -1;
}

int LcVideoReadVec::readNext(Mat & frm)
{
	if(p==-1) open();

	if(p<(int)frm_id.size()-1)
	{
		p++;
		f = frm_id[p];

		if(!IF_IMG)
		{
			cap.set( CV_CAP_PROP_POS_FRAMES, double(f));			
		}

		read_frame(frm);

		return 0;
	}
	else return -1;
}

void LcVideoReadVec::read_frame( Mat & frm)
{
	Mat temp;

	if(IF_IMG)
	{

		string vidfile = root + "vid/" + video_name + "/";

		char fname[600];		

		sprintf(fname,"%s%d%s", vidfile.c_str(), f, ext.c_str() );

		temp = imread( fname  );	
	}
	else
	{
		cap>>temp;
	}
	if(!temp.data) return;
	cv::resize( temp, frm , Size() , scale , scale);
}

int LcVideoReadVec::read( Mat & frm )
{
	if(p>=(int)frm_id.size()-1)return -1;

	if(p==-1)
	{
		open();
	}


	read_frame( frm);
	f++;
	if(!frm.data) return -1;

	if(p==int(frm_id.size()-1) || frm_id[p+1]!=f) return 1;

	p++;
	return 0;
}

